package com.collabscm.waf.solution.persistence.support;

import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

import org.springframework.stereotype.Component;

import com.collabscm.waf.exception.ApplicationException;
import com.collabscm.waf.exception.ConfigurationException;
import com.collabscm.waf.solution.logging.Logger;
import com.collabscm.waf.solution.logging.LoggerFactory;
import com.collabscm.waf.solution.persistence.DynamicQuery;
import com.collabscm.waf.solution.persistence.DynamicQueryBreakdown;
import com.collabscm.waf.solution.persistence.DynamicQueryBuilder;
import com.collabscm.waf.solution.persistence.NamedDynamicNativeQueries;
import com.collabscm.waf.solution.persistence.NamedDynamicNativeQuery;
import com.collabscm.waf.solution.persistence.NamedDynamicQueries;
import com.collabscm.waf.solution.persistence.NamedDynamicQuery;
import com.collabscm.waf.solution.persistence.WhereCondition;
import com.collabscm.waf.solution.persistence.WhereJoinType;
import com.collabscm.waf.vo.QueryParameters;

/**
 * 动态查询语句处理器
 *
 * @author Zeng Raoxing
 */
@Component
public class DefaultDynamicQueryBuilder implements DynamicQueryBuilder {
	
	/*
	 * Initialize-On-Demand Holder Class
	 * 
	private static class DynamicQueryBuilderHolder {
		private static DynamicQueryBuilder holder = new DynamicQueryBuilder();
	}
	public static DynamicQueryBuilder getInstance() {
		return DynamicQueryBuilderHolder.holder;
	}	
	private DynamicQueryBuilder() {
	}*/
	/**
	 * 解析完毕的动态查询语句的Map，其中：key可以@NamedDyanmicQuery的name，也可以是一句动态查询语句。
	 */
	private Map<String, DynamicQueryBreakdown> parsedQueryMap = new HashMap<String, DynamicQueryBreakdown>();

	private Logger logger = LoggerFactory.getLogger(DefaultDynamicQueryBuilder.class);
	
	/* (non-Javadoc)
	 * @see com.collabscm.pf.persistence.builder.DynamicQueryBuilder#buildByNamedQuery(java.lang.Class, java.lang.String, com.collabscm.pf.vo.QueryParameters)
	 */
	public DynamicQuery buildByNamedQuery(Class<?> clazz, String namedDynamicQuery, QueryParameters parameters) {
		DynamicQueryBreakdown breakdown = parsedQueryMap.get(namedDynamicQuery);
		if(breakdown == null) {//如果未找到解析的内容，那么将自动解析一下
			NamedDynamicQueries ndqs = clazz.getAnnotation(NamedDynamicQueries.class);
			for(NamedDynamicQuery ndq: ndqs.value()) {
				if(ndq.name().equals(namedDynamicQuery)) {//仅解析名称相同的NamedDynamicQuery
					breakdown = new DynamicQueryBreakdown(ndq.query());
					parsedQueryMap.put(namedDynamicQuery, breakdown);
					break;
				}
			}
		}
		if(breakdown == null) {
			throw new ConfigurationException("未在" +clazz+ "中找到NamedDynamicQuery为" +namedDynamicQuery+ "的定义");
		}
		DynamicQuery dq = buildDynamicQuery(breakdown, parameters);
		dq.setNative(false);
		return dq;
	}
	
	/* (non-Javadoc)
	 * @see com.collabscm.pf.persistence.builder.DynamicQueryBuilder#buildByNamedNativeQuery(java.lang.Class, java.lang.String, com.collabscm.pf.vo.QueryParameters)
	 */
	public DynamicQuery buildByNamedNativeQuery(Class<?> clazz, String namedDynamicQuery, QueryParameters parameters) {
		DynamicQueryBreakdown breakdown = parsedQueryMap.get(namedDynamicQuery);
		if(breakdown == null) {//如果未找到解析的内容，那么将自动解析一下
			NamedDynamicNativeQueries ndqs = clazz.getAnnotation(NamedDynamicNativeQueries.class);
			for(NamedDynamicNativeQuery ndq: ndqs.value()) {
				if(ndq.name().equals(namedDynamicQuery)) {//仅解析名称相同的NamedDynamicQuery
					breakdown = new DynamicQueryBreakdown(ndq.query());
					parsedQueryMap.put(namedDynamicQuery, breakdown);
					break;
				}
			}
		}
		if(breakdown == null) {
			throw new ConfigurationException("未在" +clazz+ "中找到NamedDynamicNativeQuery为" +namedDynamicQuery+ "的定义");
		}
		DynamicQuery dq = buildDynamicQuery(breakdown, parameters);
		dq.setNative(true);
		return dq;
	}
	
	/* (non-Javadoc)
	 * @see com.collabscm.pf.persistence.builder.DynamicQueryBuilder#buildByDynamicQuery(java.lang.String, com.collabscm.pf.persistence.WhereJoinType, com.collabscm.pf.vo.QueryParameters)
	 */
	public DynamicQuery buildByDynamicQuery(String dynamicQuery, WhereJoinType whereJoinType, QueryParameters parameters) {
		DynamicQuery dq = getDynamicQuery(dynamicQuery, whereJoinType, parameters);
		dq.setNative(false);
		return dq;
	}

	/* (non-Javadoc)
	 * @see com.collabscm.pf.persistence.builder.DynamicQueryBuilder#buildByDynamicNativeQuery(java.lang.String, com.collabscm.pf.persistence.WhereJoinType, com.collabscm.pf.vo.QueryParameters)
	 */
	public DynamicQuery buildByDynamicNativeQuery(String dynamicNativeQuery, WhereJoinType whereJoinType, QueryParameters parameters) {
		DynamicQuery dq = getDynamicQuery(dynamicNativeQuery, whereJoinType, parameters);
		dq.setNative(true);
		return dq;
	}
	
	/**
	 * @param dynamicQuery 动态的Query语句，可以是Native或非Native
	 * @param whereJoinType
	 * @param parameters
	 * @return
	 */
	private DynamicQuery getDynamicQuery(String dynamicQuery, WhereJoinType whereJoinType, QueryParameters parameters) {
		DynamicQueryBreakdown breakdown = parsedQueryMap.get(dynamicQuery);
		if(breakdown == null) {//如果未找到解析的内容，那么将自动解析一下
			breakdown = new DynamicQueryBreakdown(dynamicQuery, whereJoinType);
			parsedQueryMap.put(dynamicQuery, breakdown);
		}
		DynamicQuery dq = buildDynamicQuery(breakdown, parameters);
		return dq;
	}
	
	
	
	/* (non-Javadoc)
	 * @see com.collabscm.pf.persistence.builder.DynamicQueryBuilder#buildDynamicQuery(com.collabscm.pf.persistence.builder.DynamicQueryBreakdown, com.collabscm.pf.vo.QueryParameters)
	 */
	public DynamicQuery buildDynamicQuery(DynamicQueryBreakdown breakdown, QueryParameters parameters) {
		StringBuffer queryStatement = new StringBuffer(breakdown.getSelectClause());
		Map<String, Object> filters = parameters.getFilters();//注意：所有的过滤条件都必须在查询中有效，否则在赋值的时候会出问题。
		if(filters != null) {
			queryStatement.append(DynamicQuery.where).append(" ");
			String lastJoinString = "";
			for(WhereCondition condition: breakdown.getConditions()) {//遍历where条件，将存在的条件添加到系统内部
				String conditionStr = condition.buildCurrentCondition(filters);
				if(conditionStr != null) {
					if(lastJoinString == null) {
						throw new ApplicationException("在" + conditionStr + "前已没有连接符，解析动态查询有问题。原解析结果为:" + breakdown.descBreakdown());
					}
					queryStatement.append(lastJoinString);
					queryStatement.append(conditionStr);
					lastJoinString = condition.getContinueJoinString();
				}
			}
		} else {
			filters = Collections.emptyMap();
		}
		QueryParameters.Order order = parameters.getOrder();
		if(order != null) {
			queryStatement.append(" ").append(DynamicQuery.orderBy).append(" ");
			queryStatement.append(order.getParamName());
			if(order.isAscending()) {
				queryStatement.append(DynamicQuery.asc);
			} else {
				queryStatement.append(DynamicQuery.desc);
			}
		}
		DynamicQuery dq = new DynamicQuery();
		dq.setQueryStatement(queryStatement.toString());
		dq.setFilters(filters);
		return dq;
	}
	
	/* (non-Javadoc)
	 * @see com.collabscm.pf.persistence.builder.DynamicQueryBuilder#getDynamicQueryBreakdown(java.lang.String)
	 */
	public DynamicQueryBreakdown getDynamicQueryBreakdown(String key) {
		return this.parsedQueryMap.get(key);
	}
}
